package com.gturedi.views;

import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorProperty;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Button;
import ohos.agp.components.Component;
import ohos.agp.components.DirectionalLayout;
import ohos.agp.components.Image;
import ohos.agp.components.LayoutScatter;
import ohos.agp.components.RoundProgressBar;
import ohos.agp.components.Text;
import ohos.agp.components.element.VectorElement;
import ohos.agp.render.Canvas;
import ohos.app.Context;

/**
 * wrap the target area(component) with StatefulLayout
 */
public class StatefulLayout extends DirectionalLayout implements Component.DrawTask {

    private final String STFANIMATIONENABLED = "stfAnimationEnabled"; // 圆点半径
    private final String MSG_ONE_CHILD = "StatefulLayout must have one child!";
    private AnimatorProperty DEFAULT_IN_ANIM;
    private AnimatorProperty DEFAULT_OUT_ANIM;

    /**
     * Indicates whether to place the animation on state changes
     */
    private boolean animationEnabled = true;
    /**
     * Animation started begin of state change
     */
    private AnimatorProperty inAnimation;
    /**
     * Animation started end of state change
     */
    private AnimatorProperty outAnimation;
    /**
     * to synchronize transition animations when animation duration shorter then request of state change
     */
    private int animCounter;

    private Component content;
    private DirectionalLayout stContainer;
    private RoundProgressBar stProgress;
    private Image stImage;
    private Text stMessage;
    private Button stButton;

    public StatefulLayout(Context context) {
        this(context, null);
    }

    public StatefulLayout(Context context, AttrSet attrSet) {
        this(context, attrSet, null);
    }

    public StatefulLayout(Context context, AttrSet attrSet, String styleName) {
        super(context, attrSet, styleName);
        if (attrSet != null && attrSet.getAttr(STFANIMATIONENABLED).isPresent()) {
            animationEnabled = attrSet.getAttr(STFANIMATIONENABLED).get().getBoolValue();
        }
        DEFAULT_IN_ANIM = new AnimatorProperty().alphaFrom(0.0f).alpha(1.0f).setDuration(500);
        DEFAULT_OUT_ANIM = new AnimatorProperty().alphaFrom(1.0f).alpha(0.0f).setDuration(500);
        inAnimation = DEFAULT_IN_ANIM;
        outAnimation = DEFAULT_OUT_ANIM;
        addDrawTask(this);
    }

    @Override
    public void onDraw(Component component, Canvas canvas) {
        if (getChildCount() > 1) {
            throw new IllegalStateException(MSG_ONE_CHILD);
        }
        setOrientation(VERTICAL);
        content = getComponentAt(0); // assume first child as content
        LayoutScatter.getInstance(getContext()).parse(ResourceTable.Layout_stf_template, this, true);
        stContainer = (DirectionalLayout) findComponentById(ResourceTable.Id_stContainer);
        stProgress = (RoundProgressBar) findComponentById(ResourceTable.Id_stProgress);
        stImage = (Image) findComponentById(ResourceTable.Id_stImage);
        stMessage = (Text) findComponentById(ResourceTable.Id_stMessage);
        stButton = (Button) findComponentById(ResourceTable.Id_stButton);
    }

    public boolean isAnimationEnabled() {
        return animationEnabled;
    }

    public void setAnimationEnabled(boolean animationEnabled) {
        this.animationEnabled = animationEnabled;
    }

    public AnimatorProperty getInAnimation() {
        return inAnimation;
    }

    public void setInAnimation(AnimatorProperty animation) {
        inAnimation = animation;
    }

    public AnimatorProperty getOutAnimation() {
        return outAnimation;
    }

    public void setOutAnimation(AnimatorProperty animation) {
        outAnimation = animation;
    }

    /**
     * 显示主体内容
     */
    public void showContent() {
        if (isAnimationEnabled()) {
            final int animCounterCopy = ++animCounter;
            if (stContainer.getVisibility() == VISIBLE) {
                outAnimation.setStateChangedListener(new CustomAnimationListener() {
                    @Override
                    public void onEnd(Animator animator) {
                        if (animCounter != animCounterCopy) {
                            return;
                        }
                        stContainer.setVisibility(HIDE);
                        content.setVisibility(VISIBLE);
                        inAnimation.setTarget(content);
                        inAnimation.start();
                    }
                });
                outAnimation.setTarget(stContainer);
                outAnimation.start();
            }
        } else {
            stContainer.setVisibility(HIDE);
            content.setVisibility(VISIBLE);
        }
    }

    /**
     * 显示加载中状态
     */
    public void showLoading() {
        showLoading(ResourceTable.String_stfLoadingMessage);
    }

    /**
     * 显示加载中状态
     *
     * @param resId 加载中状态显示时的文字资源id
     */
    public void showLoading(int resId) {
        showLoading(str(resId));
    }

    /**
     * 显示加载中状态
     *
     * @param message 加载中状态显示时的文字文本内容
     */
    public void showLoading(String message) {
        showCustom(new CustomStateOptions()
                .message(message)
                .loading());
    }

    /**
     * 显示加载为空状态
     */
    public void showEmpty() {
        showEmpty(ResourceTable.String_stfEmptyMessage);
    }

    /**
     * 显示加载为空状态
     *
     * @param resId 加载为空状态显示时的文字资源id
     */
    public void showEmpty(int resId) {
        showEmpty(str(resId));
    }

    /**
     * 显示加载为空状态
     *
     * @param message 加载为空状态显示时的文字文本内容
     */
    public void showEmpty(String message) {
        showCustom(new CustomStateOptions()
                .message(message)
                .image(ResourceTable.Graphic_stf_ic_empty));
    }

    /**
     * 显示加载错误状态
     *
     * @param clickListener 加载错误状态显示时的按钮点击监听器
     */
    public void showError(ClickedListener clickListener) {
        showError(ResourceTable.String_stfErrorMessage, clickListener);
    }

    /**
     * 显示加载错误状态
     *
     * @param resId         加载错误状态显示时的文字资源id
     * @param clickListener 加载错误状态显示时的按钮点击监听器
     */
    public void showError(int resId, ClickedListener clickListener) {
        showError(str(resId), clickListener);
    }

    /**
     * 显示加载错误状态
     *
     * @param message       加载错误状态显示时的文字文本内容
     * @param clickListener 加载错误状态显示时的按钮点击监听器
     */
    public void showError(String message, ClickedListener clickListener) {
        showCustom(new CustomStateOptions()
                .message(message)
                .image(ResourceTable.Graphic_stf_ic_error)
                .buttonText(str(ResourceTable.String_stfButtonText))
                .buttonClickListener(clickListener));
    }

    /**
     * 显示加载失败（无网络）状态
     *
     * @param clickListener 加载失败状态显示时的按钮点击监听器
     */
    public void showOffline(ClickedListener clickListener) {
        showOffline(ResourceTable.String_stfOfflineMessage, clickListener);
    }

    /**
     * 显示加载失败（无网络）状态
     *
     * @param resId         加载失败状态显示时的文字资源id
     * @param clickListener 加载失败状态显示时的按钮点击监听器
     */
    public void showOffline(int resId, ClickedListener clickListener) {
        showOffline(str(resId), clickListener);
    }

    /**
     * 显示加载失败（无网络）状态
     *
     * @param message       加载失败状态显示时的文字文本内容
     * @param clickListener 加载失败状态显示时的按钮点击监听器
     */
    public void showOffline(String message, ClickedListener clickListener) {
        showCustom(new CustomStateOptions()
                .message(message)
                .image(ResourceTable.Graphic_stf_ic_offline)
                .buttonText(str(ResourceTable.String_stfButtonText))
                .buttonClickListener(clickListener));
    }

    /**
     * 显示加载失败（服务器无响应）状态
     *
     * @param clickListener 加载失败状态显示时的按钮点击监听器
     */
    public void showLocationOff(ClickedListener clickListener) {
        showLocationOff(ResourceTable.String_stfLocationOffMessage, clickListener);
    }

    /**
     * 显示加载失败（服务器无响应）状态
     *
     * @param resId         加载失败状态显示时的文字资源id
     * @param clickListener 加载失败状态显示时的按钮点击监听器
     */
    public void showLocationOff(int resId, ClickedListener clickListener) {
        showLocationOff(str(resId), clickListener);
    }

    /**
     * 显示加载失败（服务器无响应）状态
     *
     * @param message       加载失败状态显示时的文字文本内容
     * @param clickListener 加载失败状态显示时的按钮点击监听器
     */
    public void showLocationOff(String message, ClickedListener clickListener) {
        showCustom(new CustomStateOptions()
                .message(message)
                .image(ResourceTable.Graphic_stf_ic_location_off)
                .buttonText(str(ResourceTable.String_stfButtonText))
                .buttonClickListener(clickListener));
    }

    /**
     * Shows custom state for given options. If you do not set buttonClickListener, the button will not be shown
     *
     * @param options customization options
     * @see CustomStateOptions
     */
    public void showCustom(final CustomStateOptions options) {
        if (isAnimationEnabled()) {
            final int animCounterCopy = ++animCounter;
            if (stContainer.getVisibility() == HIDE) {
                outAnimation.setStateChangedListener(new CustomAnimationListener() {
                    @Override
                    public void onEnd(Animator animator) {
                        if (animCounterCopy != animCounter) {
                            return;
                        }
                        content.setVisibility(HIDE);
                        stContainer.setVisibility(VISIBLE);
                        inAnimation.setTarget(stContainer);
                        inAnimation.start();
                    }
                });
                outAnimation.setTarget(content);
                outAnimation.start();
                state(options);
            } else {
                outAnimation.setStateChangedListener(new CustomAnimationListener() {
                    @Override
                    public void onEnd(Animator animator) {
                        if (animCounterCopy != animCounter) {
                            return;
                        }
                        state(options);
                        inAnimation.setTarget(stContainer);
                        inAnimation.start();
                    }
                });
                outAnimation.setTarget(stContainer);
                outAnimation.start();
            }
        } else {
            content.setVisibility(HIDE);
            stContainer.setVisibility(VISIBLE);
            state(options);
        }
    }

    private void state(CustomStateOptions options) {
        if (!isEmpty(options.getMessage())) {
            stMessage.setVisibility(VISIBLE);
            stMessage.setText(options.getMessage());
        } else {
            stMessage.setVisibility(HIDE);
        }
        if (options.isLoading()) {
            stProgress.setVisibility(VISIBLE);
            stImage.setVisibility(HIDE);
            stButton.setVisibility(HIDE);
        } else {
            stProgress.setVisibility(HIDE);
            if (options.getImageRes() != 0) {
                stImage.setVisibility(VISIBLE);
                stImage.setImageElement(new VectorElement(getContext(), options.getImageRes()));
            } else {
                stImage.setVisibility(HIDE);
            }

            if (options.getClickListener() != null) {
                stButton.setVisibility(VISIBLE);
                stButton.setClickedListener(options.getClickListener());
                if (!isEmpty(options.getButtonText())) {
                    stButton.setText(options.getButtonText());
                }
            } else {
                stButton.setVisibility(HIDE);
            }
        }
    }

    private String str(int resId) {
        return getContext().getString(resId);
    }

    private boolean isEmpty(String str) {
        if (str != null) {
            return str.isEmpty();
        }
        return true;
    }

}
